package com.tom.demo.service.login.impl;
import cn.hutool.core.util.IdUtil;
import com.tom.demo.common.constant.CacheConstants;
import com.tom.demo.common.entity.SysMenu;
import com.tom.demo.common.entity.SysUser;
import com.tom.demo.common.utils.RecursiveMenuUtil;
import com.tom.demo.common.utils.RedisUtil;
import com.tom.demo.common.utils.SecurityUtils;
import com.tom.demo.component.TokenComponent;
import com.tom.demo.dto.LoginUserDto;
import com.tom.demo.mapper.SysMenuMapper;
import com.tom.demo.security.DetailsUser;
import com.tom.demo.service.login.LoginService;
import com.tom.demo.vo.RouterVo;
import com.tom.demo.vo.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class LoginServiceImpl implements LoginService {

    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private TokenComponent tokenComponent;

    @Resource
    private RedisUtil redisUtil;

    // 令牌有效期（默认30分钟）
    @Value("${token.expireTime}")
    private int expireTime;

    // 令牌自定义标识
    @Value("${token.header}")
    private String header;

    @Resource
    private SysMenuMapper sysMenuMapper;

    /**
     * @description
     * 这里必须要让Security中我们实现了
     * UserDetailServiceImpl去查询用户的，角色信息和权限信息，统一返回回来,不然会报错
     * @param loginUserDto
     * @return com.jack.dome.result.Result<com.jack.dome.entity.SysUser>
     * @author lanqiang
     * @date 2022/11/1 0001
     */
    @Override
    public Map<String,String> login(LoginUserDto loginUserDto) {
        //第一步:获取登录时，用户输入的账户名和密码
        String username = loginUserDto.getUsername();

        String password = loginUserDto.getPassword();

        //第二步:将我们前端传过来的参数交给Authentication的实现类UsernamePasswordAuthenticationToken
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,password);

        //第三步:会去到UserDetailServiceImpl中处理


        //第四步:现在已经是UserDetailsServiceImpl查询数据库完成以后返回的数据了
        Authentication authentication = authenticationManager.authenticate(authenticationToken);


        //第五步:从Authentication里面封装了用户从数据库查出来的数据
        DetailsUser detailsUser = (DetailsUser) authentication.getPrincipal();
        String uuid = IdUtil.simpleUUID();

        //设置过期时间是30分钟 login_tokens:uuid 用户信息
        redisUtil.setCacheObject(CacheConstants.LOGIN_TOKEN_KEY+uuid,detailsUser,expireTime, TimeUnit.MINUTES);

        //使用tokenComponent生成token
        String token = tokenComponent.createToken(uuid);

        //将token和查询出来的SysUser信息都返回给前端
        Map<String,String> tokenMap = new HashMap<>();
        tokenMap.put(header,token);

        return tokenMap;
    }

    @Override
    public UserInfoVo getUserInfo() {
        UserInfoVo userInfoVo = new UserInfoVo();
        DetailsUser detailsUser = SecurityUtils.getLoginUser();
        //获取用户信息
        SysUser sysUser = detailsUser.getSysUser();
        //当前用户的角色标识
        Set<String> roleKeys = detailsUser.getRoles()
                .stream()
                .map(roleKey -> roleKey.replaceAll("ROLE_", ""))
                .collect(Collectors.toSet());
        //当前用户的权限标识
        Set<String> permissions = detailsUser.getPermissions();
        //设置用户的基本信息
        userInfoVo.setSysUser(sysUser);
        //设置用户的角色标识
        userInfoVo.setRoles(roleKeys);
        //设置按钮的权限标识
        userInfoVo.setPermissions(permissions);
        return userInfoVo;

    }

    @Override
    public List<RouterVo> getRouters() {
        String userId = SecurityUtils.getLoginUserId();
        //查询菜单
        List<SysMenu> sysMenuList;
        if(SecurityUtils.isAdmin(userId)){
            //查询的是M和C
            sysMenuList = sysMenuMapper.findByAll();
        }else {
            //查询的是M和C
            sysMenuList = sysMenuMapper.findByUserId(userId);
        }
        if(sysMenuList != null && !sysMenuList.isEmpty()){
            //构建前段需要的路由结构
            List<SysMenu> sysMenus = RecursiveMenuUtil.buildMenuTree(sysMenuList);
            return RecursiveMenuUtil.buildRouter(sysMenus);
        }
        return null;
    }

}
